package cn.xiaolang.function.network.multiplexing;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * TODO
 *
 * @author Dean
 * @date 2022-02-13
 */
public class TCPReactor implements Runnable {

    private final ServerSocketChannel ssc;
    private final Selector selector;

    public TCPReactor(int port) throws IOException {
        selector = Selector.open();
        ssc = ServerSocketChannel.open();
        InetSocketAddress addr = new InetSocketAddress(port);
        ssc.socket().bind(addr);
        ssc.configureBlocking(false);
        // ServerSocketChannel向selector注册一个OP_ACCEPT事件，然后返回该通道的key
        SelectionKey sk = ssc.register(selector, SelectionKey.OP_ACCEPT);
        // 给定key一个附加的Acceptor对象
        sk.attach(new Acceptor(selector, ssc));

    }

    @Override
    public void run() {

        while (!Thread.interrupted()) {
            System.out.println("Waiting for new event on port: " + ssc.socket().getLocalPort() + "...");
            try {
                // 如果没有事件就绪则不往下执行
                if (selector.select() == 0) {
                    System.out.println("no select event ...");
                    continue;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 取得所有已就绪事件的key集合
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator it = selectedKeys.iterator();
            while (it.hasNext()) {
                // 根据事件的key进行调度
                dispatch((SelectionKey) (it.next()));
                it.remove();

            }

        }

    }

    /*
     * name: dispatch(SelectionKey key)
     * description: 调度方法，根据事件绑定的对象开新线程
     */
    private void dispatch(SelectionKey key) {
        Runnable r = (Runnable) (key.attachment());
        if (r != null)
            r.run();
    }
}

